package com.shuai.robot.mq;

import cn.hutool.core.text.CharSequenceUtil;
import com.rabbitmq.client.Channel;
import com.shuai.common.constant.ChartAnalysisStatus;
import com.shuai.common.constant.ErrorCode;
import com.shuai.common.constant.RabbitMQExchangeEnum;
import com.shuai.common.constant.RabbitQueueEnum;
import com.shuai.common.dto.AnalysisErrorMsgDTO;
import com.shuai.common.dto.ChartQueryDTO;
import com.shuai.common.dto.ChartUpdateDTO;
import com.shuai.common.exception.BusinessException;
import com.shuai.common.service.analysis.InnerAnalysisService;
import com.shuai.robot.dto.ChatModelRps;
import com.shuai.robot.service.AIInteractService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class ChartAnalysisListener {

    @DubboReference
    private InnerAnalysisService innerAnalysisService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private AIInteractService aiInteractService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @RabbitListener(queues = "xs.AI.station.common.queue", ackMode = "MANUAL")
    public void receiveChartMessage(String message,
                                    Channel channel,
                                    @Header(AmqpHeaders.DELIVERY_TAG) long deliverTag)
            throws IOException {
        log.info("接收到图表消息：{}，开始进行处理", message);
        // 记录消息是第几次处理
        String operationCountStr = stringRedisTemplate.opsForValue().get(message);
        if (CharSequenceUtil.isBlank(operationCountStr)) {
            stringRedisTemplate.opsForValue().set(message, "1");
            operationCountStr = "1";
        }
        int operationCount = Integer.parseInt(operationCountStr);
        log.info("图表{}处理第{}次", message, operationCount);
        if (operationCount > 3) {
            log.info("图表{}处理失败次数过多，转发到失败队列进行人工处理", message);
            // 向死信交换机转发消息
            rabbitTemplate.convertAndSend(RabbitMQExchangeEnum.ERROR_MSG_XS_AI_STATION.name,
                    RabbitQueueEnum.ERROR_QUEUE_XS_AI_STATION.routingKey,
                    message);
            stringRedisTemplate.delete(message);
            channel.basicAck(deliverTag, false);
            return;
        }
        try {
            // 从数据库中查询出这条图表信息拿到图表数据，分析目标，生成的图表类型，更新图表的状态
            ChartQueryDTO chartInfo = innerAnalysisService.getChartInfo(message);
            if (chartInfo == null) {
                log.info("图表{}信息不存在", message);
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "图表信息不存在");
            }
            // 更新图标状态为处理中
            innerAnalysisService.updateChartInfo(ChartUpdateDTO.builder()
                    .id(chartInfo.getId())
                    .status(ChartAnalysisStatus.PROCESSING.getCode())
                    .build());

            // 构建prompt语句
            String prompt = this.buildPromptForChartAnalysis(chartInfo);

            // 调用AI模型取得响应结果
            ChatModelRps chatModelRps = aiInteractService.interactAskOnce(prompt, String.valueOf(chartInfo.getUserId()));
            if (chatModelRps == null || chatModelRps.getCode() != 0) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI模型无响应");
            }
            // 解析响应结果
            List<String> formatData = this.processXFResponseData(chatModelRps.getChoices().get(0).getMessage().getContent());
            if (formatData == null || formatData.size() != 2) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI模型数据格式错误");
            }
            // 将响应结果更新到图表信息表中，同时更新图表状态
            ChartUpdateDTO updateDTO = ChartUpdateDTO.builder()
                    .id(chartInfo.getId())
                    .genData(formatData.get(0))
                    .genConclusion(formatData.get(1))
                    .status(ChartAnalysisStatus.SUCCESS.getCode())
                    .errorLog("")
                    .build();
            innerAnalysisService.updateChartInfo(updateDTO);
        } catch (Exception e) {
            log.info("处理图表{}失败：{}", message, e.getMessage());
            // 更新图标状态为处理失败
            innerAnalysisService.updateChartInfo(ChartUpdateDTO.builder()
                    .id(Long.parseLong(message))
                    .status(ChartAnalysisStatus.FAILURE.getCode())
                    .errorLog(e.getMessage())
                    .build());
            channel.basicNack(deliverTag, false, true);
            throw new RuntimeException(e);
        } finally {
            stringRedisTemplate.opsForValue().increment(message);
        }
        channel.basicAck(deliverTag, false);
    }

    private String buildPromptForChartAnalysis(ChartQueryDTO chartInfo) {
        String promptTemplate = stringRedisTemplate.opsForValue().get("xs-AI-station-chart-analysis");
        if (CharSequenceUtil.isBlank(promptTemplate)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "图表分析prompt模板缺失");
        }
        return promptTemplate.replace("%{goal}", chartInfo.getGoal())
                .replace("%{chart_data}", chartInfo.getChartData());
    }

    private List<String> processXFResponseData(String responseMessage) {
        if (responseMessage == null) {
            return null;
        }
        String[] split = responseMessage.split("%%%%%");
        List<String> splitList = Arrays.stream(split)
                .filter(s -> s != null && !CharSequenceUtil.isBlank(s.trim()))
                .collect(Collectors.toList());
        if (splitList.size() != 2) {
            return null;
        }
        // 校验AI返回的图表数据是否正确
        if (!this.secondCheckUseParenthesisMatching(splitList.get(0))) {
            return null;
        }
        return splitList;
    }

    /**
     * 括号匹配校验AI接口的返回结果
     */
    private boolean secondCheckUseParenthesisMatching(String content) {
        // 寻找第一个大括号
        int startPos = content.indexOf("{");
        content = content.substring(startPos);
        char[] contentCharacters = content.toCharArray();
        // 括号匹配栈
        Stack<Character> charactersStack = new Stack<>();
        for (int i = 0; i < contentCharacters.length; i++) {
            char contentCharacter = contentCharacters[i];
            if (contentCharacter == '{' || contentCharacter == '(' || contentCharacter == '[') {
                // 入栈
                charactersStack.push(contentCharacter);
            } else if (contentCharacter == '}' || contentCharacter == ')' || contentCharacter == ']') {
                // 匹配出栈
                Character peek = charactersStack.peek();
                if (!peek.equals('{') && contentCharacter == '}'
                        || !peek.equals('[') && contentCharacter == ']'
                        || !peek.equals('(') && contentCharacter == ')') {
                    return false;    // AI返回的代码结果有误
                } else {
                    charactersStack.pop();
                }
            }
            // 如果栈为空了，说明匹配结束。
            if (charactersStack.isEmpty()) {
                content = content.substring(0, i + 1);
                break;
            }
        }
        if (!charactersStack.isEmpty()) {
            return false;
        }
        return true;
    }
}




